namespace hms::swe
{

template<typename MeshType>
template<BlockLocation loc>
void SolverThread<MeshType>::computeFluxes_cell(
	const Block<loc>& block,
	const Array3XsMap& q,
	      Array3XsMap& fluxes,
	const Array1XsMap& h,
	const Ref<const ArrayXXs>& d,
	const Ref<const ArrayXXs>& z,
	const Ref<const ArrayXXs>& v,
	const MeshBase<MeshType>& mesh
){
	using RT = ReconstructionType;
	using ER = EdgeRange;

	#ifndef NDEBUG
	auto cell { mesh.derived().cell(block.xBeg() - 1, block.yBeg() - 1) };
	mesh.logger().trace(
		"Block beg: {}, cell (i,j,#): {}, {}, {}, edges: {}",
		block.firstCell().transpose(),
		cell.i(),
		cell.j(),
		cell.index(),
		cell.edges().transpose()
	);

	auto checkEdgeIndex = [&](
		RT rt,
		ER orien,
		Index edge,
		const auto& lr_block
	){
		if ( edge >= mesh.nEdges() ){
			mesh.logger().error(
				"{}: Edge index {} is greater than number of edges in mesh ({})!"
				"\nCell: {}, first h edge: {}, first v edge: {}"
				"\nEdges according to mesh.cell(...).edges(): {}",
				bold(red("Error")),
				edge,
				mesh.nEdges(),
				block.firstCell().transpose() - block.ih().mesh.ng,
				block.hBeg(),
				block.vBeg()
				, cell.edges().transpose()
			);
		} else {
			mesh.logger().trace(
				"{}#{}, {}, {}, lr_block: {}",
				indent(),
				edge,
				magic_enum::enum_name(orien),
				magic_enum::enum_name(rt),
				lr_block.transpose()
			);
		}
	};
	#define CHECK_EDGE(...) checkEdgeIndex(__VA_ARGS__)
	#else
	#define CHECK_EDGE(...)
	#endif

	#define HLLC(REC_TYPE, EDGE_RANGE, EDGE_INDEX, LR_BLOCK) \
	CHECK_EDGE(REC_TYPE, EDGE_RANGE, EDGE_INDEX, LR_BLOCK); \
	fluxScheme<REC_TYPE, EDGE_RANGE>( \
		block, q, fluxes, h, d, z, v, mesh, EDGE_INDEX, LR_BLOCK)

	#define HLLC_BOT(REC_TYPE) \
	HLLC( REC_TYPE, ER::horizontal, block.hBeg(), \
		block.template lrBeg_block<ER::horizontal>() )

	#define HLLC_TOP(REC_TYPE) \
	HLLC( REC_TYPE, ER::horizontal, block.hBeg() + block.ih().mesh.nx, \
		block.template lrBeg_block<ER::horizontal>() + block.nxRead() )

	#define HLLC_LFT(REC_TYPE) \
	HLLC( REC_TYPE, ER::vertical, block.vBeg(), \
		block.template lrBeg_block<ER::vertical>() )

	#define HLLC_RGT(REC_TYPE) \
	HLLC( REC_TYPE, ER::vertical, block.vBeg() + 1, \
		block.template lrBeg_block<ER::vertical>() + 1 )


	if constexpr ( atMiddleRows<loc>() ){
		HLLC_BOT(RT::secondOrder);
		HLLC_TOP(RT::secondOrder);
	} else {
		if ( atTop<loc>() && block.yBeg() == block.ih().beg.outerY ){
			HLLC_BOT(RT::secondOrder);
		} else {
			HLLC_BOT(RT::central);
		}
		if (atBottom<loc>() && block.yBeg() == block.ih().beg.blocks - 1){
			HLLC_TOP(RT::secondOrder);
		} else {
			HLLC_TOP(RT::central);
		}
	}

	if constexpr ( atMiddleCols<loc>() ){
		HLLC_LFT(RT::secondOrder);
		HLLC_RGT(RT::secondOrder);
	} else {
		if ( atRight<loc>() && block.xBeg() == block.ih().beg.outerX ){
			HLLC_LFT(RT::secondOrder);
		} else {
			HLLC_LFT(RT::central);
		}
		if (atLeft<loc>() && block.xBeg() == block.ih().beg.blocks - 1){
			HLLC_RGT(RT::secondOrder);
		} else {
			HLLC_RGT(RT::central);
		}
	}

	#undef HLLC_BOT
	#undef HLLC_TOP
	#undef HLLC_LFT
	#undef HLLC_RGT
	#undef HLLC
}

} // namespace hms::swe
